#pragma once
#include <vector>
#include "VoxelCore.h"

namespace BVHIndex{

using namespace std;
// 
// struct Point3d
// {
// 	double x, y, z;
// 
// 	Point3d();
// 	Point3d(double in_x, double in_y, double in_z):x(in_x),y(in_y),z(in_z){}
// 	Point3d operator +(Point3d pt){return Point3d(pt.x + x, pt.y + y, pt.z + z);}
// 	Point3d operator -(Point3d pt){return Point3d(pt.x - x, pt.y - y, pt.z - z);}
// 	Point3d operator =(Point3d pt){return Point3d(pt.x, pt.y , pt.z);}
// };
// typedef Point3d Vector3d;
// typedef shared_ptr<Point3d> ptr_Point;
// typedef vector<Point3d> Pointlist;
// 
// struct Indice3i
// {
// 	int x, y, z;
// 
// 	Indice3i();
// 	Indice3i(int in_x, int in_y, int in_z):x(in_x),y(in_y),z(in_z){}
// 	Indice3i operator +(Indice3i pt){return Indice3i(pt.x + x, pt.y + y, pt.z + z);}
// 	Indice3i operator =(Indice3i pt){return Indice3i(pt.x, pt.y , pt.z);}
// };
// 
// struct Triangle3
// {
// 	int vert[3];
// };
// typedef shared_ptr<Triangle3> ptr_Triangle;
// typedef vector<Triangle3> Trianglelist;
// 
// struct Polygon3
// {
// 	vector<int> ExteriorRing;
// 	vector<vector<int>> InteriorRings;
// };
// typedef shared_ptr<Polygon3> ptr_Polygon;
// typedef vector<Polygon3> Polygonlist;
// 
// struct Surface3
// {
// 	Trianglelist facets;
// };
// 
// struct Polyhedron3
// {
// 	Trianglelist facets;
// };
// 
// struct BoundingBox
// {
// 	Indice3i Max;
// 	Indice3i Min;
// 
// 	BoundingBox();
// 	BoundingBox(Indice3i ptMax, Indice3i ptMin):Max(ptMax), Min(ptMin){}
// 	BoundingBox(Pointlist, double);
// 	BoundingBox operator =(BoundingBox box){return BoundingBox(box.Max, box.Min);}
// 	Indice3i GetSize();
// 	int GetMaxSize();
// };
// 
// class CVoxel
// {
// private:
// 	//properties
// 	bool bOccupied;
// 
// 	//spatial extent
// 	BoundingBox BBox;
// 
// public:
// 	//construction
// 	CVoxel();
// 	CVoxel(bool bTag, BoundingBox box):bOccupied(bTag), BBox(box){}
// 	virtual ~CVoxel();
// 
// public:
// 	//operations
// 	void SetOccupied(bool);
// 	void SetBBox(BoundingBox);
// 	//
// 	bool GetOccupied();
// 	BoundingBox GetBBox();
// 	Point3d GetCenter(double);
// };
// 
// typedef shared_ptr<CVoxel> ptr_CVoxel;
// typedef vector<ptr_CVoxel> VoxelptrList;

class CBVHVoxelIndex  
{
private:
	//
	typedef shared_ptr<CBVHVoxelIndex> ptr_BVHNode;

	//Data
//	ptr_CVoxel VoxelData;

	//parent
	ptr_BVHNode parent;

	//2 children
	vector<ptr_BVHNode> children;

	//voxelsize
//	double dVoxelSize;

	//spatial extent
//	BoundingBox BBox;

private:
	//manipulate operations
	ptr_BVHNode GetRoot();
	//ptr_BVHNode GetParent();
	//vector<ptr_BVHNode> GetChildren();
	int CountDepth(ptr_BVHNode);
	void QuerybyBbox(VoxelCore::Point3d, VoxelCore::Point3d, vector<ptr_BVHNode> &);
	void GetVoxels(vector<VoxelCore::ptr_CVoxel>&);
	//construction operation
	ptr_BVHNode ConstructChildren(VoxelCore::BoundingBox, ptr_BVHNode);

public:
	//////////////////////////////////////////////////////////////////////////
	//global Operations

	//Query operations
 	VoxelCore::ptr_CVoxel QuerybyPoint(VoxelCore::Point3d);
 	VoxelCore::vector<VoxelCore::ptr_CVoxel> QuerybyBbox(VoxelCore::Point3d, VoxelCore::Point3d);
// 	vector<ptr_CVoxel> QuerybyShell(Polyhedron3, Pointlist);
 	VoxelCore::vector<VoxelCore::ptr_CVoxel> QuerybySurface(VoxelCore::Surface3, VoxelCore::Pointlist);

	//Output voxels to vtk
//	bool WriteVoxels(string);

	//////////////////////////////////////////////////////////////////////////
	//local Operations
//	BoundingBox GetBBox();
	int GetBVHDepth();
	int GetNodeDepth(ptr_BVHNode Node);

	//Fetch operations
//	ptr_CVoxel GetData();
	
	//Query operations
	bool IsRoot();
	bool IsLeaf();

public:
	//construction
	CBVHVoxelIndex();
	CBVHVoxelIndex(VoxelCore::Pointlist, double);
	virtual ~CBVHVoxelIndex();
};

typedef shared_ptr<CBVHVoxelIndex> ptr_BVHNode;

}



















